﻿using Edu.Abstracts;
using Edu.Contracts;
using Edu.Entitys;
using Edu.Utilities;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Linq.Dynamic.Core;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.Application.Dtos;
using Volo.Abp.AutoMapper;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.Linq;

namespace Edu.Services
{
    public class TaskPostSuggestDto
    {
        public Guid Id { get; set; }
        public string Suggest { get; set; }
    }

    public class TaskPostContentDto
    {
        public Guid Id { get; set; }
        public string Detail { get; set; }
  
        public string Experience { get; set; }

        public string Title { get; set; }

        public string Suggest { get; set; }

        public AbilityType AbilityType { get; set; }

        public System.DateTimeOffset DeadLine
        {
            get;
            set;
        }
    }

    public class TaskPostScoreDto
    {
        public Guid Id { get; set; }
        public int Score { get; set; }
    }

    public class TaskPostStatusDto
    {
        public Guid Id { get; set; }
        public StudyTaskStatus Status { get; set; }
    }


    [AutoMapTo(typeof(StudyTaskContent))]
    public class TaskPostCreateDto
    {
        public string Title
        {
            get;
            set;
        }

        /// <summary>
        /// 截止时间
        /// </summary>
        public System.DateTimeOffset DeadLine
        {
            get;
            set;
        }

        /// <summary>
        /// 老师的uid
        /// </summary>
        public Guid TeacherId
        {
            get;
            set;
        }

        /// <summary>
        /// 学生的uid
        /// </summary>
        public Guid StudentId
        {
            get;
            set;
        }

        public string One { get; set; }

        public string Two { get; set; }

        public string Three { get; set; }

        public string TaskType { get; set; }

        public string Detail { get; set; }


        public string Grade { get; set; }

        public string Experience { get; set; }

        [Required]
        public AbilityType AbilityType { get; set; }

    }


    public class StudyTaskAppService : WeChatAppServiceBase
    {
        public IAsyncQueryableExecuter AsyncQueryableExecuter { get; set; }

        private readonly UserAchievementAppService userAchievementAppService;
        private readonly RatingAppService ratingAppService;
        private readonly IRepository<AppStudent, Guid> students;

        public IRepository<AppStudyTask, Guid> Repository { get; }

        public StudyTaskAppService(IRepository<AppStudyTask, Guid> repository,
            IRepository<AppStudent, Guid> students,
            RatingAppService ratingAppService,
            UserAchievementAppService userAchievementAppService
            )
        {
            this.userAchievementAppService = userAchievementAppService;
            this.ratingAppService = ratingAppService;
            this.students = students;
            this.Repository = repository;
            AsyncQueryableExecuter = DefaultAsyncQueryableExecuter.Instance;
        }



        public async Task<object> UpdateContent(TaskPostContentDto dto)
        {
            var task = await this.Repository.GetAsync(dto.Id);

            try
            {
                task.Content.Detail = dto.Detail;
                task.Content.Experience = dto.Experience;
                task.AbilityType = dto.AbilityType;
                task.Suggest = dto.Suggest;
                task.Title = dto.Title;
                task.DeadLine = dto.DeadLine;
                await this.Repository.UpdateAsync(task, true);
            }
            catch (Microsoft.EntityFrameworkCore.DbUpdateException)
            {
                throw new UserFriendlyException("内容中包含非法字符或者表情");
            }
            return new { };
        }

        public async Task<object> UpdateSuggest(TaskPostSuggestDto dto)
        {
            var task = await this.Repository.GetAsync(dto.Id);
            task.Suggest = dto.Suggest;
            await this.Repository.UpdateAsync(task, true);
            return ObjectMapper.Map<AppStudyTask, StudyTaskDto>(task);
        }

        public async Task<StudyTaskDto> UpdateTeacherScore(TaskPostScoreDto dto)
        {
            var task = await this.Repository.GetAsync(dto.Id);
            task.TeacherScore = dto.Score;
            await this.Repository.UpdateAsync(task, true);
            return ObjectMapper.Map<AppStudyTask, StudyTaskDto>(task);
        }

        public async Task<StudyTaskDto> UpdateScore(TaskPostScoreDto dto)
        {
            var task = await this.Repository.GetAsync(dto.Id);
            task.Score = dto.Score;

            await this.Repository.UpdateAsync(task, true);

            return ObjectMapper.Map<AppStudyTask, StudyTaskDto>(task);
        }


        private Dictionary<AbilityLevelType, int> AbilityUpgradeLevelNum = new Dictionary<AbilityLevelType, int>()
        {
            {AbilityLevelType.RuMen,3},
            {AbilityLevelType.JinJie,6},
            {AbilityLevelType.GaoJie,9},
            {AbilityLevelType.JieYe,int.MaxValue }
        };


        public Dictionary<AbilityType, int> GetStudentAbilitys(Guid studentId)
        {
            var tasks = this.Repository.Where(g => g.StudentId == studentId && g.Status == StudyTaskStatus.Complete).ToList();
            return GetAbilitys(tasks);
        }

        private Dictionary<AbilityType, int> GetAbilitys(List<AppStudyTask> tasks)
        {

            var abilitys = new Dictionary<AbilityType, int>();

            var abilityNums = new Dictionary<AbilityType, int>();

            foreach (var item in tasks)
            {
                if (abilitys.TryGetValue(item.AbilityType, out var abilityType) == false)
                {
                    abilitys.Add(item.AbilityType, 0);
                    abilityNums.Add(item.AbilityType, 0);
                }
                abilitys[item.AbilityType] += item.Score ?? 0;
                abilityNums[item.AbilityType] += 1;
            }

            var result = new Dictionary<AbilityType, int>();

            foreach (var item in abilitys)
            {
                result.Add(item.Key, item.Value * 20 / abilityNums[item.Key]);
            }

            return result;
        }




        private async Task UpdateAbility(Guid studentId, AbilityType abilityType)
        {
            var student = students.Single(a => a.UserId == studentId);

            if (student.Abilitys == null)
            {
                this.InitStudentAbilitys(student);
            }

            if (student.Abilitys.TryGetValue(abilityType, out var value) == false)
            {
                value = this.AddDefaultAbility(student, abilityType);
            }
            value.TaskNum += 1;
            if (value.TaskNum >= 3)
            {
                //充值完成任务数
                value.TaskNum = 0;
                //总勋章+1
                value.Total++;
                //晋升需要的勋章+1
                value.Num++;
                if (value.Num >= AbilityUpgradeLevelNum[value.Level])
                {
                    var nextLevelInt = (int)value.Level + 1;
                    nextLevelInt = nextLevelInt >= 3 ? 3 : nextLevelInt;
                    value.Level = (AbilityLevelType)(nextLevelInt);
                    value.Num = 0;

                    if ((int)value.Level == 2)
                    {
                        await userAchievementAppService.HandlerAbilityGaoJie(student);
                    }
                }

                await userAchievementAppService.HandlerAbilityXunZhang(student);
            }

            await students.UpdateAsync(student, true);
        }


        private void InitStudentAbilitys(AppStudent student)
        {
            student.Abilitys = new Dictionary<AbilityType, AbilityTypeLevel>();

            if (student.Job == JobType.XiangMuZong)
            {
                for (int i = 5; i < 11; i++)
                {
                    this.AddDefaultAbility(student, (AbilityType)i);
                }
            }
            else if (student.Job == JobType.YingXiaoJingLi)
            {
                for (int i = 0; i < 5; i++)
                {
                    this.AddDefaultAbility(student, (AbilityType)i);
                }
            }
        }

        private AbilityTypeLevel AddDefaultAbility(AppStudent student, AbilityType abilityType)
        {
            var value = new AbilityTypeLevel()
            {
                Level = AbilityLevelType.RuMen,
                Num = 0,
                Total = 0,
                TaskNum = 0
            };
            student.Abilitys.TryAdd(abilityType, value);
            return value;
        }

        public async Task<object> UpdateStatus(TaskPostStatusDto dto)
        {
            var task = await this.Repository.GetAsync(dto.Id);
            task.Status = dto.Status;
            if (task.Status == StudyTaskStatus.UnScore)
            {
                task.CompleteTime = DateTimeOffset.Now;
            }
            if (task.Status == StudyTaskStatus.Studying)
            {
                task.ReviewTime = DateTimeOffset.Now;
            }
            await this.Repository.UpdateAsync(task, true);
            return new { };
        }


        public async Task<StudyTaskDto> CreateAsync(TaskPostCreateDto dto)
        {
            var now = DateTimeOffset.Now;

            if (dto.DeadLine > now.EndOfQuarter())
            {
                throw new UserFriendlyException("截止日期不能超过本季度");
            }
            try
            {
                var entity = new AppStudyTask()
                {
                    Id = GuidGenerator.Create(),
                    Year = now.Year,
                    Quarter = now.GetQuarter(),
                    Title = dto.Title,
                    DeadLine = dto.DeadLine,
                    TeacherId = dto.TeacherId,
                    StudentId = dto.StudentId,
                    Status = StudyTaskStatus.Pending,
                    Content = new StudyTaskContent(),
                    AbilityType = dto.AbilityType
                };

                ObjectMapper.Map(dto, entity.Content);
                await this.Repository.InsertAsync(entity, true);
                return ObjectMapper.Map<AppStudyTask, StudyTaskDto>(entity);
            }
            catch (Microsoft.EntityFrameworkCore.DbUpdateException)
            {

                throw new UserFriendlyException("内容中包含非法字符或者表情");
            }

        }

        public int GetAllScore(Guid studentId)
        {
            return this.Repository.Where(g => g.StudentId == studentId && g.Score != null).Select(a => a.Score.Value).Sum();
        }

        public async Task<StudyTaskDto> GetTaskDetail(Guid taskId)
        {
            var task = await this.Repository.GetAsync(taskId);
            return ObjectMapper.Map<AppStudyTask, StudyTaskDto>(task);
        }

        /// <summary>
        /// 获取用户的任务(学生)
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<PagedResultDto<StudyTaskDto>> GetTasksAsync(Guid studentId, int year, int quarter, PagedAndSortedResultRequestDto input)
        {
            var (totalCount, entities) = await GetAndCheckExpired(studentId, year, quarter, input);

            return new PagedResultDto<StudyTaskDto>(
                totalCount,
                entities.Select(MapToEntityDto).ToList()
            );
        }

        public async Task<(int, List<AppStudyTask>)> GetAndCheckExpired(Guid studentId, int year, int quarter, PagedAndSortedResultRequestDto input)
        {
            input.MaxResultCount = 100000;

            var query = CreateFilteredQuery(input);
            var date = DateTimeOffset.Now;
            query = query.Where(a => a.StudentId == studentId && a.Year == year && a.Quarter == quarter);

            var totalCount = await AsyncQueryableExecuter.CountAsync(query);

            query = query.ApplySorting(input);
            query = query.ApplyPaging(input);
            var entities = await AsyncQueryableExecuter.ToListAsync(query);

            foreach (var item in entities)
            {
                if (item.Status != StudyTaskStatus.Studying)
                {
                    continue;
                }
                //检查是否过期
                var today = DateTimeOffset.Now;
                if ((item.DeadLine - today).Days < 0)
                {
                    item.Status = StudyTaskStatus.Expired;
                    await this.Repository.UpdateAsync(item, true);
                }
            }

            return (totalCount, entities);
        }


        public async Task<List<StudyTaskDto>> GetPendingTasksAsync(Guid studentId)
        {
            var query = this.Repository.Where(a => a.Status == StudyTaskStatus.AdminPending && a.StudentId == studentId);
            var entities = await AsyncQueryableExecuter.ToListAsync(query);
            return entities.Select(MapToEntityDto).ToList();
        }

        public async Task<StudentAbilityInfo> GetHistoryAbilityAsync(Guid studentId, PagedAndSortedResultRequestDto input)
        {
            var student = students.Single(a => a.UserId == studentId);

            var date = DateTimeOffset.UtcNow;
            var currentQ = date.GetQuarter();
            var currentY = date.Year;

            //todo 缓存 
            var result = new StudentAbilityInfo()
            {
                Id = student.UserId,
                Job = student.Job,
                Items = new List<StudentAbilityHistoryDto>()
            };
            var entities = result.Items;
            for (int i = currentY; i >= student.JoinYear; i--)
            {
                var noInRange = false;
                //currentQ 从当前季度算
                for (int j = currentQ; j > 0; j--)
                {
                    var (_, tasks) = await GetAndCheckExpired(student.UserId, i, j, input);
                    var rating = await ratingAppService.GetOrAddRating(student.UserId, student.TeacherId, i, j);
                    var entity = new StudentAbilityHistoryDto()
                    {
                        Year = i,
                        Quarter = j,
                        Abilitys = GetAbilitys(tasks),
                        Score = 0,
                        CompleteNum = 0,
                        UnCompleteNum = 0,
                        OtherNum = 0,
                        HasStudentRate = rating.StudentTime.HasValue,
                        StudentRate = rating.StudentScore,
                        HasTeacherRate = rating.TeacherTime.HasValue,
                        TeacherRate = rating.TeacherScore
                    };

                    foreach (var task in tasks)
                    {
                        entity.Score += task.Score ?? 0;

                        if (task.Status == StudyTaskStatus.Complete)
                        {
                            entity.CompleteNum++;
                        }
                        else if (StudyTaskStatusIf.UnComplete(task.Status))
                        {
                            entity.UnCompleteNum++;
                        }
                        else
                        {
                            entity.OtherNum++;
                        }
                    }

                    if (i == student.JoinYear && j <= student.JoinQuarter && tasks.Count == 0)
                    {
                        //当拜师季度的任务为0则不计入历史
                    }
                    else
                    {
                        entities.Add(entity);
                    }
                    if (i == student.JoinYear && j <= student.JoinQuarter)
                    {
                        noInRange = true;
                        break;
                    }
                }

                if (noInRange == true)
                {
                    break;
                }
                currentQ = 4;//最大是4 
            }


            return result;
        }


        public async Task<PagedResultDto<StudyTaskHistoryDto>> GetHistoryAsync(Guid studentId, PagedAndSortedResultRequestDto input)
        {
            var student = students.Single(a => a.UserId == studentId);

            var date = DateTimeOffset.UtcNow;
            var currentQ = date.GetQuarter();
            var currentY = date.Year;

            //todo 缓存
            var entities = new List<StudyTaskHistoryDto>();
            for (int i = currentY; i >= student.JoinYear; i--)
            {
                var noInRange = false;
                for (int j = currentQ - 1; j > 0; j--)
                {
                    var (_, tasks) = await GetAndCheckExpired(student.UserId, i, j, input);

                    var rating = await ratingAppService.GetOrAddRating(student.UserId, student.TeacherId, i, j);

                    var entity = new StudyTaskHistoryDto()
                    {
                        Year = i,
                        Quarter = j,
                        Score = 0,
                        CompleteNum = 0,
                        UnCompleteNum = 0,
                        OtherNum = 0,
                        HasStudentRate = rating.StudentTime.HasValue,
                        StudentRate = rating.StudentScore,
                        HasTeacherRate = rating.TeacherTime.HasValue,
                        TeacherRate = rating.TeacherScore
                    };

                    foreach (var task in tasks)
                    {
                        entity.Score += task.Score ?? 0;

                        if (task.Status == StudyTaskStatus.Complete)
                        {
                            entity.CompleteNum++;
                        }
                        else if (StudyTaskStatusIf.UnComplete(task.Status))
                        {
                            entity.UnCompleteNum++;
                        }
                        else
                        {
                            entity.OtherNum++;
                        }
                    }

                    //特殊需求。。加入的季度未必有任务则不显示
                    if (i == student.JoinYear && j <= student.JoinQuarter && tasks.Count == 0)
                    {
                        //当拜师季度的任务为0则不计入历史
                    }
                    else
                    {
                        entities.Add(entity);
                    }
                    if (i == student.JoinYear && j <= student.JoinQuarter)
                    {
                        noInRange = true;
                        break;
                    }

                }

                if (noInRange == true)
                {
                    break;
                }
                currentQ = 5;//最大是4  j以currentQ - 1计算..因为是历史不计算当前季度
            }


            return new PagedResultDto<StudyTaskHistoryDto>(
               entities.Count,
               entities
            );
        }


        private StudyTaskDto MapToEntityDto(AppStudyTask entity)
        {
            return ObjectMapper.Map<AppStudyTask, StudyTaskDto>(entity);
        }

        protected virtual IQueryable<AppStudyTask> CreateFilteredQuery(PagedAndSortedResultRequestDto input)
        {
            return Repository;
        }

        public async Task<string> GetTaskProgress(Guid studentId, int year, int quarter)
        {
            var query = Repository.Where(a => a.StudentId == studentId && a.Year == year && a.Quarter == quarter);
            var entities = await AsyncQueryableExecuter.ToListAsync(query);

            var completeCount = 0;
            var totalCount = 0;

            foreach (var task in entities)
            {
                if (task.Status == StudyTaskStatus.Complete)
                {
                    completeCount++;
                }
                if (task.Status != StudyTaskStatus.Reject)
                {
                    totalCount++;
                }
            }
            return $"{completeCount}/{totalCount}";
        }

    }
}
